﻿
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Common;

namespace CatEars.Core.Data
{
    /// <summary>
    /// 连接串提供类（收录各种连接串）
    /// </summary>
    public static class DbConnStringProvider
    {
        /// <summary>
        /// 静态初始化
        /// </summary>
        static DbConnStringProvider()
        {
            Init();
        }

        static void Init()
        {
            m_drivers = new Dictionary<string, DbConnStr>(StringComparer.OrdinalIgnoreCase);
            DbConnStr conn;
            conn = new Sqlite();
            m_drivers["Sqlite"] = conn;
            conn = new Mysql();
            m_drivers["Mysql"] = conn;
            m_drivers["MysqlClient"] = conn;
            conn = new Sqlserver();
            m_drivers["Sqlserver"] = conn;
            m_drivers["SqlClient"] = conn;

            conn = new Oledb();
            m_drivers["Oledb"] = conn;
            conn = new OledbToAccess();
            m_drivers["OledbToAccess"] = conn;
            conn = new OlddbToExcel();
            m_drivers["OlddbToExcel"] = conn;
            conn = new OlddbToText();
            m_drivers["OlddbToText"] = conn;
        }

        /// <summary>
        /// 驱动缓存
        /// </summary>
        static Dictionary<string, DbConnStr> m_drivers;

        /// <summary>
        /// 支持的驱动
        /// </summary>
        public static IEnumerable<string> DirverNames { get { return m_drivers.Keys; } }

        /// <summary>
        /// 根据驱动名称获取驱动
        /// </summary>
        /// <param name="strDriverName">驱动名称</param>
        /// <returns>驱动工厂</returns>
        public static DbConnStr GetDbConnStr(string strDriverName)
        {
            DbConnStr result;
            m_drivers.TryGetValue(strDriverName, out result);
            return result;
        }

        /// <summary>
        /// 连接串提供类 接口
        /// </summary>
        public class DbConnStr
        {
            /// <summary>
            /// 数据文件(文件类型的)
            /// </summary>
            [DisplayName("文件路径")]
            public string FileSource { get; protected set; }

            /// <summary>
            /// 数据源(服务器类型的)（若没设置ServerPort，则端口号接在ServerHost后面）
            /// </summary>
            [DisplayName("服务器实例")]
            public string ServerHost { get; protected set; }

            /// <summary>
            /// 数据源
            /// </summary>
            [DisplayName("服务端口")]
            public string ServerPort { get; protected set; }

            /// <summary>
            /// 用户ID
            /// </summary>
            [DisplayName("用户ID")]
            public string UserID { get; protected set; }

            /// <summary>
            /// 密码
            /// </summary>
            [DisplayName("用户密码")]
            public string Password { get; protected set; }

            /// <summary>
            /// 数据库
            /// </summary>
            [DisplayName("数据库")]
            public string Database { get; protected set; }

            /// <summary>
            /// 连接超时
            /// </summary>
            [DisplayName("连接超时")]
            public string ConnTimeout { get; protected set; }

            /// <summary>
            /// 默认连接串生成器
            /// </summary>
            /// <returns>连接串生成器</returns>
            public virtual DbConnectionStringBuilder CreateBuilder()
            {
                return new DbConnectionStringBuilder();
            }

            /// <summary>
            /// 生成连接串
            /// </summary>
            /// <param name="strFileFullName">文件名</param>
            /// <returns>连接串</returns>
            public virtual DbConnectionStringBuilder ConnToFile(string strFileFullName)
            {
                if (string.IsNullOrEmpty(FileSource)) throw new NotSupportedException();
                if (string.IsNullOrEmpty(strFileFullName)) throw new NotSupportedException("必须指定文件名");
                DbConnectionStringBuilder builder = CreateBuilder();
                AddToBuilder(builder, FileSource, strFileFullName);
                return builder;
            }

            /// <summary>
            /// 生成连接串
            /// </summary>
            /// <param name="strHost">服务器地址</param>
            /// <param name="intPort">服务器端口</param>
            /// <param name="strUserID">用户ID</param>
            /// <param name="strPassword">密码</param>
            /// <param name="strDatabase">文件名</param>
            /// <param name="intConnTimeout">文件名</param>
            /// <returns>连接串</returns>
            public virtual DbConnectionStringBuilder ConnToServer(
                string strHost,
                int intPort,
                string strUserID,
                string strPassword,
                string strDatabase,
                int intConnTimeout = -1)
            {
                if (string.IsNullOrEmpty(ServerHost)) throw new NotSupportedException();
                DbConnectionStringBuilder builder = CreateBuilder();
                if (string.IsNullOrEmpty(strHost))
                {
                    strHost = "localhost";
                }
                AddToBuilder(builder, ServerHost, strHost);
                if (intPort > 0)
                {
                    if (string.IsNullOrEmpty(ServerPort))
                    {
                        AddToBuilder(builder, ServerHost, strHost + ":" + intPort);
                    }
                    else
                    {
                        AddToBuilder(builder, ServerPort, intPort);
                    }
                }
                AddToBuilder(builder, UserID, strUserID);
                AddToBuilder(builder, Password, strPassword);
                AddToBuilder(builder, Database, strDatabase);
                if (intConnTimeout > 0)
                {
                    AddToBuilder(builder, ConnTimeout, intConnTimeout);
                }
                return builder;
            }

            /// <summary>
            /// 添加参数到DbConnectionStringBuilder
            /// </summary>
            /// <param name="builder"></param>
            /// <param name="strKey"></param>
            /// <param name="objValue"></param>
            public static void AddToBuilder(DbConnectionStringBuilder builder,
                string strKey,
                object objValue)
            {
                if (builder == null || string.IsNullOrEmpty(strKey)) return;
                if (objValue == null)
                {
                    builder.Remove(strKey);
                }
                else
                {
                    string strValue = objValue as string;
                    if (strValue == null)
                    {
                        strValue = objValue.ToString();
                    }
                    if (string.IsNullOrEmpty(strValue))
                    {
                        builder.Remove(strKey);
                    }
                    else
                    {
                        builder.Add(strKey, objValue);
                    }
                }
            }

            /// <summary>
            /// 添加参数到DbConnectionStringBuilder
            /// </summary>
            /// <param name="builder"></param>
            /// <param name="strKey"></param>
            /// <param name="strValue"></param>
            public static void AddToBuilder(DbConnectionStringBuilder builder,
                string strKey,
                string strValue)
            {
                if (builder == null || string.IsNullOrEmpty(strKey)) return;
                if (string.IsNullOrEmpty(strValue))
                {
                    builder.Remove(strKey);
                }
                else
                {
                    builder.Add(strKey, strValue);
                }
            }
        }

        /// <summary>
        /// Sqlite数据库
        /// </summary>
        public class Sqlite : DbConnStr
        {

            /// <summary>
            /// Sqlite数据库
            /// </summary>
            public Sqlite()
            {
                base.FileSource = "Data Source";
            }
        }

        /// <summary>
        /// Mysql数据库
        /// </summary>
        public class Mysql : DbConnStr
        {
            /// <summary>
            /// Mysql数据库
            /// </summary>
            public Mysql()
            {
                base.ServerHost = "Server";
                base.ServerPort = "Port";
                base.UserID = "User Id";
                base.Password = "Password";
                base.Database = "Database";
                base.ConnTimeout = "ConnectionTimeout";
            }
        }

        /// <summary>
        /// Sqlserver数据库
        /// </summary>
        public class Sqlserver : DbConnStr
        {
            /// <summary>
            /// Sqlserver数据库
            /// </summary>
            public Sqlserver()
            {
                base.ServerHost = "Data Source";
                base.UserID = "User ID";
                base.Password = "Password";
                base.Database = "Initial Catalog";
                base.ConnTimeout = "ConnectTimeout";
            }

            /// <summary>
            /// 生成连接串
            /// </summary>
            /// <param name="strHost">服务器地址</param>
            /// <param name="intPort">服务器端口</param>
            /// <param name="strUserID">用户ID</param>
            /// <param name="strPassword">密码</param>
            /// <param name="strDatabase">文件名</param>
            /// <param name="intConnTimeout">文件名</param>
            /// <returns>连接串</returns>
            public override DbConnectionStringBuilder ConnToServer(
                string strHost,
                int intPort,
                string strUserID,
                string strPassword,
                string strDatabase,
                int intConnTimeout = -1)
            {
                if (string.IsNullOrEmpty(strUserID))
                {
                    strPassword = null;
                    DbConnectionStringBuilder builder = base.ConnToServer(
                        strHost, intPort, strUserID, strPassword, strDatabase, intConnTimeout);
                    //没有用户名密码的 使用本机帐号登录
                    AddToBuilder(builder, "Integrated Security", "SSPI");
                    return builder;
                }
                else
                {
                    return base.ConnToServer(
                           strHost, intPort, strUserID, strPassword, strDatabase, intConnTimeout);
                }
            }
        }

        #region 基于Oledb
        /// <summary>
        /// Oledb通用驱动
        /// </summary>
        public class Oledb : DbConnStr
        {
            /// <summary>
            /// OldDb扩展参数
            /// </summary>
            [DisplayName("Oledb驱动类型")]
            public string OleDbProvider { get; protected set; }

            /// <summary>
            /// OldDb扩展参数
            /// </summary>
            [DisplayName("Oledb扩展参数")]
            public string OleDbExpProp { get; protected set; }

            /// <summary>
            /// Oledb通用驱动
            /// </summary>
            public Oledb()
            {
                base.FileSource = "Data Source";
                OleDbProvider = "Provider";
                OleDbExpProp = "Extended Properties";
            }

            /// <summary>
            /// Provider4 "Microsoft.Jet.OLEDB.4.0"
            /// </summary>
            public static readonly string Provider = "Microsoft.Jet.OLEDB.4.0";
            /// <summary>
            /// Provider12(office2007) "Microsoft.ACE.OLEDB.12.0"
            /// </summary>
            public static readonly string Provider12 = "Microsoft.ACE.OLEDB.12.0";

            /// <summary>
            /// 默认的Provider
            /// </summary>
            public virtual string GetDefaultProvider(string strFileName)
            {
                return Provider;
            }

            /// <summary>
            /// 生成连接串
            /// </summary>
            /// <param name="strFileFullName">文件名</param>
            /// <returns>连接串</returns>
            public override DbConnectionStringBuilder ConnToFile(string strFileFullName)
            {
                return ConnToFile(strFileFullName, null);
            }

            /// <summary>
            /// 生成连接串
            /// </summary>
            /// <param name="strFileFullName">文件名</param>
            /// <param name="strProvider">驱动</param>
            /// <param name="strExtProp">扩展参数</param>
            /// <returns>连接串</returns>
            public virtual DbConnectionStringBuilder ConnToFile(string strFileFullName,
                string strProvider,
                string strExtProp = null)
            {
                if (string.IsNullOrEmpty(strFileFullName)) throw new NotSupportedException("必须指定文件名");

                DbConnectionStringBuilder builder = CreateBuilder();
                AddToBuilder(builder, FileSource, strFileFullName);
                if (string.IsNullOrEmpty(strProvider))
                {
                    strProvider = GetDefaultProvider(strFileFullName);
                }
                AddToBuilder(builder, OleDbProvider, strProvider);
                strExtProp = strExtProp.Trim();
                if (!string.IsNullOrEmpty(strExtProp))
                {
                    if (strExtProp[0] != '\'') strExtProp = '\'' + strExtProp + '\'';
                    AddToBuilder(builder, OleDbExpProp, strExtProp);
                }
                return builder;
            }
        }

        /// <summary>
        /// Access数据库
        /// </summary>
        public class OledbToAccess : Oledb
        {
            /// <summary>
            /// OledbToAccess
            /// </summary>
            public OledbToAccess()
            {
                base.OleDbExpProp = null;
            }

            /// <summary>
            /// 默认的Provider
            /// </summary>
            public override string GetDefaultProvider(string strFileName)
            {
                if (strFileName.EndsWith(".accdb", StringComparison.OrdinalIgnoreCase))
                {
                    return Provider12;
                }
                return Provider;
            }
        }

        /// <summary>
        /// Excel文件
        /// </summary>
        public class OlddbToExcel : Oledb
        {
            /// <summary>
            /// OlddbToExcel
            /// </summary>
            public OlddbToExcel() { }

            /// <summary>
            /// 生成连接串
            /// </summary>
            /// <param name="strFileFullName">文件名</param>
            /// <param name="strProvider">驱动</param>
            /// <param name="strExtProp">扩展参数</param>
            /// <returns>连接串</returns>
            public override DbConnectionStringBuilder ConnToFile(string strFileFullName,
                string strProvider,
                string strExtProp = null)
            {
                if (string.IsNullOrEmpty(strExtProp))
                {
                    strExtProp = "'Excel 8.0;HDR=False;IMEX=2'";
                }
                return base.ConnToFile(strFileFullName, strProvider, strExtProp);
            }
        }

        /// <summary>
        /// 平面文本文件(txt,csv)
        /// </summary>
        public class OlddbToText : Oledb
        {
            /// <summary>
            /// OlddbToText
            /// </summary>
            public OlddbToText() { }

            /// <summary>
            /// 生成连接串
            /// </summary>
            /// <param name="strFileFullName">文件名</param>
            /// <param name="strProvider">驱动</param>
            /// <param name="strExtProp">扩展参数</param>
            /// <returns>连接串</returns>
            public override DbConnectionStringBuilder ConnToFile(string strFileFullName,
                string strProvider,
                string strExtProp = null)
            {
                if (string.IsNullOrEmpty(strExtProp))
                {
                    strExtProp = "'text;HDR=YES;FMT=TabDelimited'";
                }
                return base.ConnToFile(strFileFullName, strProvider, strExtProp);
            }
        }
        #endregion
    }
}
